package com.wugh.fast.module.web;

import cn.hutool.core.util.ArrayUtil;
import com.wugh.fast.kernel.core.enums.FastExceptionEnum;
import com.wugh.fast.kernel.core.exception.FastBusinessException;
import com.wugh.fast.kernel.core.exception.FastExceptionMark;
import com.wugh.fast.module.api.vo.ResponseVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

/**
 * @author WUGH
 * @date 2018/5/10
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = Throwable.class)
    @ResponseBody
    public ResponseVO defaultErrorHandler(HttpServletRequest req, Throwable e) {
        FastExceptionMark mark = convertFromOrSuppressedThrowable(e, FastExceptionMark.class, true);
        if (mark != null) {
            return ResponseVO.fail(mark);
        } else {
            FastBusinessException exception = new FastBusinessException(e, FastExceptionEnum.UNHANDLED_EXCEPTION);
            return ResponseVO.fail(exception);
        }
    }

    public static <T> T convertFromOrSuppressedThrowable(Throwable throwable, Class<T> exceptionClass, boolean checkCause) {
        if (throwable == null || exceptionClass == null) {
            return null;
        }
        if (exceptionClass.isAssignableFrom(throwable.getClass())) {
            return (T) throwable;
        }
        if (checkCause) {
            Throwable cause = throwable.getCause();
            if (cause != null && exceptionClass.isAssignableFrom(cause.getClass())) {
                return (T) cause;
            }
        }
        Throwable[] throwables = throwable.getSuppressed();
        if (ArrayUtil.isNotEmpty(throwables)) {
            for (Throwable throwable1 : throwables) {
                if (exceptionClass.isAssignableFrom(throwable1.getClass())) {
                    return (T) throwable1;
                }
            }
        }
        return null;
    }

}
